```html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>有效的括号 | 算法可视化</title>
    <link href="https://cdn.staticfile.org/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
    <link href="https://cdn.staticfile.org/tailwindcss/2.2.19/tailwind.min.css" rel="stylesheet">
    <link href="https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;500;600;700&family=Noto+Sans+SC:wght@300;400;500;700&display=swap" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/mermaid@latest/dist/mermaid.min.js"></script>
    <style>
        body {
            font-family: 'Noto Sans SC', 'Noto Serif SC', Tahoma, Arial, Roboto, "Droid Sans", "Helvetica Neue", "Droid Sans Fallback", "Heiti SC", "Hiragino Sans GB", Simsun, sans-serif;
            background-color: #f8fafc;
            color: #1e293b;
        }
        .hero-gradient {
            background: linear-gradient(135deg, #4f46e5 0%, #7c3aed 100%);
        }
        .code-bg {
            background-color: #1e293b;
            color: #f8fafc;
        }
        .card-hover:hover {
            transform: translateY(-4px);
            box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
        }
        .stack-animation {
            transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
        }
        .stack-item {
            box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
        }
        .highlight {
            position: relative;
            z-index: 1;
        }
        .highlight:after {
            content: '';
            position: absolute;
            bottom: 2px;
            left: 0;
            width: 100%;
            height: 30%;
            background-color: rgba(79, 70, 229, 0.3);
            z-index: -1;
            transform: scaleX(0.9);
            transition: all 0.3s ease;
        }
        .highlight:hover:after {
            height: 40%;
            background-color: rgba(79, 70, 229, 0.4);
        }
    </style>
</head>
<body>
    <!-- Hero Section -->
    <section class="hero-gradient text-white py-20 px-6 md:py-32">
        <div class="max-w-4xl mx-auto text-center">
            <h1 class="text-4xl md:text-6xl font-bold mb-6 tracking-tight">有效的括号</h1>
            <p class="text-xl md:text-2xl font-light leading-relaxed max-w-3xl mx-auto">
                探索如何用<span class="font-medium highlight">栈数据结构</span>优雅地解决括号匹配问题
            </p>
            <div class="mt-10 flex justify-center space-x-4">
                <a href="#problem" class="px-6 py-3 bg-white text-indigo-700 font-medium rounded-lg hover:bg-opacity-90 transition duration-300 shadow-md">
                    <i class="fas fa-question-circle mr-2"></i>问题详解
                </a>
                <a href="#visualization" class="px-6 py-3 bg-indigo-800 text-white font-medium rounded-lg hover:bg-indigo-900 transition duration-300 shadow-md">
                    <i class="fas fa-project-diagram mr-2"></i>可视化演示
                </a>
            </div>
        </div>
    </section>

    <!-- Main Content -->
    <div class="max-w-6xl mx-auto px-6 py-16">
        <!-- Problem Section -->
        <section id="problem" class="mb-24">
            <div class="flex items-center mb-10">
                <div class="h-1 w-16 bg-indigo-600 mr-4"></div>
                <h2 class="text-3xl font-bold text-gray-800">问题描述</h2>
            </div>
            
            <div class="grid md:grid-cols-2 gap-12">
                <div>
                    <div class="bg-white rounded-xl shadow-lg p-8 mb-8 card-hover transition duration-300">
                        <h3 class="text-xl font-semibold mb-4 text-indigo-700 flex items-center">
                            <i class="fas fa-brackets-curly mr-3"></i>题目要求
                        </h3>
                        <p class="text-gray-600 leading-relaxed">
                            给定一个只包含 '(', ')', '{', '}', '[', ']' 的字符串，判断字符串是否有效。有效字符串需满足：
                        </p>
                        <ul class="mt-4 space-y-2 text-gray-600">
                            <li class="flex items-start">
                                <i class="fas fa-check-circle text-indigo-500 mt-1 mr-2"></i>
                                <span>左括号必须用相同类型的右括号闭合</span>
                            </li>
                            <li class="flex items-start">
                                <i class="fas fa-check-circle text-indigo-500 mt-1 mr-2"></i>
                                <span>左括号必须以正确的顺序闭合</span>
                            </li>
                        </ul>
                    </div>

                    <div class="bg-white rounded-xl shadow-lg p-8 card-hover transition duration-300">
                        <h3 class="text-xl font-semibold mb-4 text-indigo-700 flex items-center">
                            <i class="fas fa-brain mr-3"></i>核心考点
                        </h3>
                        <div class="flex items-center bg-indigo-50 rounded-lg p-4 mb-4">
                            <div class="flex-shrink-0 h-12 w-12 rounded-full bg-indigo-100 flex items-center justify-center">
                                <i class="fas fa-layer-group text-indigo-600 text-xl"></i>
                            </div>
                            <div class="ml-4">
                                <h4 class="font-medium text-gray-800">栈数据结构</h4>
                                <p class="text-gray-600 text-sm">后进先出(LIFO)的特性完美匹配括号匹配需求</p>
                            </div>
                        </div>
                        <p class="text-gray-600 leading-relaxed">
                            栈(Stack)是一种线性数据结构，遵循后进先出(LIFO)原则。在括号匹配问题中，我们利用栈来保存遇到的左括号，当遇到右括号时与栈顶元素进行匹配检查。
                        </p>
                    </div>
                </div>

                <div>
                    <div class="bg-white rounded-xl shadow-lg overflow-hidden card-hover transition duration-300">
                        <div class="p-6 bg-indigo-700 text-white">
                            <h3 class="text-xl font-semibold flex items-center">
                                <i class="fas fa-code mr-3"></i>算法思路
                            </h3>
                        </div>
                        <div class="p-6">
                            <ol class="space-y-4 text-gray-700">
                                <li class="flex items-start">
                                    <span class="flex-shrink-0 h-6 w-6 rounded-full bg-indigo-100 text-indigo-800 flex items-center justify-center font-medium mr-3">1</span>
                                    <span>使用栈存储左括号</span>
                                </li>
                                <li class="flex items-start">
                                    <span class="flex-shrink-0 h-6 w-6 rounded-full bg-indigo-100 text-indigo-800 flex items-center justify-center font-medium mr-3">2</span>
                                    <span>遇到右括号时检查栈顶是否匹配</span>
                                </li>
                                <li class="flex items-start">
                                    <span class="flex-shrink-0 h-6 w-6 rounded-full bg-indigo-100 text-indigo-800 flex items-center justify-center font-medium mr-3">3</span>
                                    <span>若不匹配或栈为空，返回 False</span>
                                </li>
                                <li class="flex items-start">
                                    <span class="flex-shrink-0 h-6 w-6 rounded-full bg-indigo-100 text-indigo-800 flex items-center justify-center font-medium mr-3">4</span>
                                    <span>遍历结束时检查栈是否为空</span>
                                </li>
                            </ol>

                            <div class="mt-8">
                                <div class="flex justify-between items-center mb-3">
                                    <h4 class="font-medium text-gray-800">复杂度分析</h4>
                                </div>
                                <div class="grid grid-cols-2 gap-4">
                                    <div class="bg-gray-50 rounded-lg p-4">
                                        <div class="text-indigo-600 font-medium mb-1">时间复杂度</div>
                                        <div class="text-gray-600">O(n)</div>
                                    </div>
                                    <div class="bg-gray-50 rounded-lg p-4">
                                        <div class="text-indigo-600 font-medium mb-1">空间复杂度</div>
                                        <div class="text-gray-600">O(n)</div>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </section>

        <!-- Code Section -->
        <section class="mb-24">
            <div class="flex items-center mb-10">
                <div class="h-1 w-16 bg-indigo-600 mr-4"></div>
                <h2 class="text-3xl font-bold text-gray-800">示例代码</h2>
            </div>

            <div class="bg-white rounded-xl shadow-lg overflow-hidden">
                <div class="flex items-center bg-gray-800 px-6 py-3">
                    <div class="flex space-x-2 mr-4">
                        <div class="h-3 w-3 rounded-full bg-red-500"></div>
                        <div class="h-3 w-3 rounded-full bg-yellow-500"></div>
                        <div class="h-3 w-3 rounded-full bg-green-500"></div>
                    </div>
                    <div class="text-gray-300 text-sm">Java - isValid.java</div>
                </div>
                <div class="p-6 overflow-x-auto">
                    <pre class="code-bg text-gray-200 p-6 rounded-lg text-sm md:text-base"><code>public boolean isValid(String s) {
    // 创建栈用于存储左括号
    Stack&lt;Character&gt; stack = new Stack&lt;&gt;();
    
    // 创建哈希表，键为右括号，值为对应的左括号
    Map&lt;Character, Character&gt; brackets = new HashMap&lt;&gt;();
    brackets.put(')', '(');
    brackets.put('}', '{');
    brackets.put(']', '[');
    
    // 遍历字符串中的每个字符
    for (char c : s.toCharArray()) {
        // 如果是左括号，入栈
        if (c == '(' || c == '{' || c == '[') {
            stack.push(c);
        } 
        // 如果是右括号
        else if (brackets.containsKey(c)) {
            // 如果栈为空或栈顶元素与当前右括号不匹配，返回false
            if (stack.isEmpty() || stack.pop() != brackets.get(c)) {
                return false;
            }
        }
    }
    
    // 最终检查栈是否为空，为空则所有括号都匹配
    return stack.isEmpty();
}</code></pre>
                </div>
            </div>
        </section>

        <!-- Visualization Section -->
        <section id="visualization" class="mb-16">
            <div class="flex items-center mb-10">
                <div class="h-1 w-16 bg-indigo-600 mr-4"></div>
                <h2 class="text-3xl font-bold text-gray-800">可视化演示</h2>
            </div>

            <div class="grid md:grid-cols-2 gap-12">
                <div>
                    <div class="bg-white rounded-xl shadow-lg p-8 h-full">
                        <h3 class="text-xl font-semibold mb-6 text-indigo-700">栈操作模拟</h3>
                        <div class="flex items-end justify-center h-64 border-b-2 border-gray-200 relative">
                            <!-- Stack visualization will be inserted here by JS -->
                            <div id="stack-visualization" class="w-full flex flex-col items-center space-y-2 absolute bottom-0 px-4">
                                <!-- Stack items will be added here dynamically -->
                                <div class="text-gray-500 text-sm py-8">输入字符串开始模拟栈操作...</div>
                            </div>
                        </div>
                        <div class="mt-8">
                            <div class="flex items-center justify-between mb-4">
                                <div class="font-medium">输入字符串:</div>
                                <div class="flex space-x-2">
                                    <input type="text" id="input-string" value="({[]})" class="border border-gray-300 rounded px-3 py-1 w-48">
                                    <button id="run-btn" class="bg-indigo-600 text-white px-4 py-1 rounded hover:bg-indigo-700 transition">执行</button>
                                </div>
                            </div>
                            <div id="execution-status" class="text-gray-600 text-sm italic"></div>
                        </div>
                    </div>
                </div>

                <div>
                    <div class="bg-white rounded-xl shadow-lg p-8 h-full">
                        <h3 class="text-xl font-semibold mb-6 text-indigo-700">算法流程图</h3>
                        <div class="mermaid">
                            graph TD
                                A[开始] --> B[初始化栈和哈希表]
                                B --> C[遍历字符串]
                                C --> D{当前字符是左括号?}
                                D -- 是 --> E[入栈]
                                D -- 否 --> F{是右括号?}
                                F -- 是 --> G{栈为空或栈顶不匹配?}
                                G -- 是 --> H[返回False]
                                G -- 否 --> I[出栈]
                                F -- 否 --> C
                                C --> J{遍历完成?}
                                J -- 否 --> C
                                J -- 是 --> K{栈为空?}
                                K -- 是 --> L[返回True]
                                K -- 否 --> H
                        </div>
                    </div>
                </div>
            </div>
        </section>

        <!-- Concept Map Section -->
        <section class="mb-16">
            <div class="bg-white rounded-xl shadow-lg p-8">
                <h3 class="text-xl font-semibold mb-6 text-indigo-700 flex items-center">
                    <i class="fas fa-sitemap mr-3"></i>概念关系图
                </h3>
                <div class="mermaid">
                    mindmap
                        root((有效的括号))
                            核心数据结构
                                栈(Stack)
                                    LIFO原则
                                    基本操作
                                        push
                                        pop
                                        peek
                                        isEmpty
                            匹配规则
                                类型匹配
                                顺序正确
                            常见应用场景
                                代码解析
                                表达式求值
                                HTML/XML标签匹配
                            相关算法
                                递归解法
                                双指针(有限场景)
                            进阶问题
                                带优先级括号
                                最小插入次数使括号有效
                </div>
            </div>
        </section>
    </div>

    <script>
        mermaid.initialize({
            startOnLoad: true,
            theme: 'default',
            flowchart: {
                useMaxWidth: true,
                htmlLabels: true,
                curve: 'basis'
            }
        });

        document.addEventListener('DOMContentLoaded', function() {
            const runBtn = document.getElementById('run-btn');
            const inputString = document.getElementById('input-string');
            const stackVisualization = document.getElementById('stack-visualization');
            const executionStatus = document.getElementById('execution-status');

            const bracketPairs = {
                ')': '(',
                '}': '{',
                ']': '['
            };

            runBtn.addEventListener('click', function() {
                const s = inputString.value;
                stackVisualization.innerHTML = '';
                executionStatus.textContent = '执行中...';
                
                let stack = [];
                let isValid = true;
                let delay = 0;

                // Reset button state
                runBtn.disabled = true;
                runBtn.classList.add('opacity-50');

                for (let i = 0; i < s.length; i++) {
                    const c = s[i];
                    setTimeout(() => {
                        const charDiv = document.createElement('div');
                        charDiv.className = 'bg-indigo-100 text-indigo-800 px-4 py-2 rounded-lg mb-2';
                        charDiv.textContent = `当前字符: '${c}' (位置 ${i})`;
                        stackVisualization.prepend(charDiv);

                        if (c === '(' || c === '{' || c === '[') {
                            // Push to stack
                            stack.push(c);
                            updateStackVisualization(stack);
                            executionStatus.textContent = `将 '${c}' 压入栈中`;
                        } else if (bracketPairs[c]) {
                            // Check if matches top of stack
                            if (stack.length === 0 || stack[stack.length - 1] !== bracketPairs[c]) {
                                isValid = false;
                                executionStatus.textContent = `错误: '${c}' 与栈顶不匹配`;
                                showError();
                                return;
                            } else {
                                stack.pop();
                                updateStackVisualization(stack);
                                executionStatus.textContent = `'${c}' 匹配成功，弹出栈顶元素`;
                            }
                        }
                    }, delay);
                    delay += 1000;
                }

                setTimeout(() => {
                    if (isValid) {
                        if (stack.length === 0) {
                            executionStatus.textContent = '所有括号匹配成功！字符串有效。';
                            showSuccess();
                        } else {
                            executionStatus.textContent = `错误: 栈不为空，剩余未匹配括号: ${stack.join(', ')}`;
                            showError();
                        }
                    }
                    runBtn.disabled = false;
                    runBtn.classList.remove('opacity-50');
                }, delay);
            });

            function updateStackVisualization(stack) {
                const stackItems = document.querySelectorAll('.stack-item');
                stackItems.forEach(item => item.remove());
                
                if (stack.length === 0) {
                    const emptyMsg = document.createElement('div');
                    emptyMsg.className = 'stack-item bg-gray-100 text-gray-500 px-4 py-2 rounded-lg text-center w-16';
                    emptyMsg.textContent = '空';
                    stackVisualization.appendChild(emptyMsg);
                } else {
                    [...stack].reverse().forEach((item, index) => {
                        const stackItem = document.createElement('div');
                        stackItem.className = `stack-item bg-indigo-600 text-white px-4 py-2 rounded-lg text-center w-16 mb-1 stack-animation ${index === 0 ? 'bg-indigo-700' : ''}`;
                        stackItem.textContent = item;
                        stackItem.title = index === 0 ? '栈顶' : '';
                        stackVisualization.appendChild(stackItem);
                    });
                }
            }

            function showError() {
                executionStatus.classList.remove('text-green-600');
                executionStatus.classList.add('text-red-600');
            }

            function showSuccess() {
                executionStatus.classList.remove('text-red-600');
                executionStatus.classList.add('text-green-600');
            }

            // Initialize empty stack visualization
            updateStackVisualization([]);
        });
    </script>
</body>
</html>
```